import { Router } from '@angular/router';
import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ConfigStateService, LocalizationService } from '@abp/ng.core';
import { EditState } from 'joy-abpui-angular';
import { UniqueCodeSettingService } from '../../core/unique-code-setting/unique-code-setting.service';
import { UnitDto, UnitGroupDto, AuxiliaryUnitDto, UnitGroupService, UnitService } from '../../proxy/joy/erp/basic-archives/item-masters';
import { UnitRefSelectService } from '../unit-ref-select/unit-ref-select.services';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { map } from 'rxjs/operators';
import { debounce } from '../../core/debounce.util';

@Component({
  selector: 'lib-unit-group-daw-multi-entity',
  templateUrl: './unit-group-daw-multi-entity.component.html',
  styleUrls: ['./unit-group-daw-multi-entity.component.less'],
})
export class UnitGroupDawMultiEntityComponent implements OnInit {
  entityConfig = {
    defaultValue: {
    },
  };

  @Input() id?: string;

  editState: EditState;
  validateForm: FormGroup;
  currentEntity: UnitGroupDto;

  get codeInputDisabled() {
    var uniqueCodeConfigration = this.config.getSetting("UniqueCodeConfigration:Joy.Erp.BasicArchives.ItemMasters.UnitGroup");
    var uniqueCodeConfigrationObj = JSON.parse(uniqueCodeConfigration);
    return uniqueCodeConfigrationObj["AutoCode"];
  }

  showMainUnitSelect = (selectedUnit: UnitDto) => {
    var modalRef = this.unitRefSelectService.show(selectedUnit ? [selectedUnit] : [], { multiple: false });

    return modalRef.afterClose.pipe(
      map(selectedUnits => {
        if (selectedUnits && selectedUnits.length > 0) {
          return selectedUnits[0];
        }
        return null;
      })
    );
  }

  getMainUnitDetail = (mainUnitId: string) => {
    return this.unitService.get(mainUnitId);
  }

  get children(): FormArray {
    return this.validateForm.get('children') as FormArray;
  }

  constructor(
    public router: Router,
    public fb: FormBuilder,
    public config: ConfigStateService,
    public message: NzMessageService,
    public modal: NzModalService,
    public modalService: NzModalService,
    public localizationService: LocalizationService,
    public unitService: UnitService,
    public entityService: UnitGroupService,
    private unitRefSelectService: UnitRefSelectService,
    private nzContextMenuService: NzContextMenuService,
    private uniqueCodeSettingService: UniqueCodeSettingService,
  ) {}

  ngOnInit(): void {
    this.editState = EditState.Empty;
    this.currentEntity = this.entityConfig.defaultValue as UnitGroupDto;
    this.validateForm = this.fb.group({
      code: [this.entityConfig.defaultValue['code'], [Validators.required, Validators.maxLength(200)]],
      groupName: [this.entityConfig.defaultValue['groupName'], [Validators.required, Validators.maxLength(20)]],
      mainUnitId: [this.entityConfig.defaultValue['mainUnitId'], [Validators.required]],
      children: this.fb.array([])
    });    
    this.updateCodeValidators();

    if (this.id) {
      this.entityService.get(this.id).subscribe(entity => {
        if (entity) {
          this.setCurrentEntity(entity);
        }
      });
    }

    this.validateForm.valueChanges.subscribe(_ => {
      if (this.editState == EditState.Empty) {
        this.editState = EditState.Creating;
      } else if (this.editState == EditState.View) {
        this.editState = EditState.Editing;
      }
    });
    
    this.updateCodeValidators();
  }

  createChildFormGroup(child?: AuxiliaryUnitDto) {
    return this.fb.group({
      id: [child?.id],
      mainArchiveId: [this.currentEntity?.id],
      unitId: [child?.unitId, [Validators.required]],
      mainToAuxiliaryRatio: [child?.mainToAuxiliaryRatio, [Validators.required]],
      auxiliaryToMainRatio: [child?.auxiliaryToMainRatio, [Validators.required]],
      sourceType: [child?.sourceType],
      sourceKey: [child?.sourceKey],
      lastModificationTime: [child?.lastModificationTime],
      lastModifierId: [child?.lastModifierId],
      creationTime: [child?.creationTime],
      creatorId: [child?.creatorId],
    });
  }

  addChild() {
    this.children.push(this.createChildFormGroup());
  }

  removeChild(index: number) {
    this.children.removeAt(index);
  }

  @debounce()
  save() {
    // 检查整个表单的验证状态
    if (this.validateForm.invalid) {
      // 标记所有控件为已触摸状态，触发验证显示
      this.markFormGroupTouched(this.validateForm);
      this.message.error(this.l('BasicArchives::UI:Message.ValidationError'));
      return;
    }

    // 检查子表单的验证状态
    if (this.children.invalid) {
      this.markFormGroupTouched(this.validateForm);
      this.message.error('请检查子表单的验证错误');
      return;
    }

    if (this.editState == EditState.Creating) {
      this.entityService
        .create({ ...this.validateForm.value })
        .subscribe(entity => {
          if (!!entity) {
            this.setCurrentEntity(entity);
            this.message.success(this.l('BasicArchives::UI:Message.AddSuccess'));
          }
        });
    } else if (this.editState == EditState.Editing) {
      this.entityService
        .update(this.currentEntity.id, {
          ...this.currentEntity,
          ...this.validateForm.value
        })
        .subscribe(entity => {
          if (!!entity) {
            this.setCurrentEntity(entity);
            this.message.success(this.l('BasicArchives::UI:Message.EditSuccess'));
          }
        });
    }
  }

  @debounce()
  giveup() {
    this.giveUpConfirm().then(_ => {
      if (this.editState == EditState.Creating) {
        //表单状态为创建时，清空数据
        this.changeToEmpty();
      } else if (this.editState == EditState.Editing) {
        //表单状态为编辑时，恢复原数据
        this.setCurrentEntity(this.currentEntity);
      }
    });
  }

  @debounce()
  new() {
    this.checkDirty().then(_ => this.changeToEmpty());
  }

  @debounce()
  copy() {
    this.checkDirty().then(_ => {
      this.setCurrentEntity({...this.currentEntity, code: ""});
      this.currentEntity = this.entityConfig.defaultValue as UnitGroupDto;
      this.editState = EditState.Creating;
    });
  }

  @debounce()
  delete() {
    this.modal.confirm({
      nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
      nzContent: this.l('BasicArchives::UI:Confirm.Content.DeleteConfirm'),
      nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
      nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
      nzOnOk: () => {
        this.entityService.delete(this.currentEntity.id).subscribe(_ => this.changeToEmpty());
      },
    });
  }

  @debounce()
  refresh() {    
    if(this.currentEntity.id) {
      this.entityService.get(this.currentEntity.id).subscribe(entity => {
        if (!!entity) {
          this.setCurrentEntity(entity);
        }
      });
    } else {      
      this.changeToEmpty();
    }
  }

  @debounce()
  search(code) {
    if(code) {
      this.entityService.find(code).subscribe(entity => {
        if (!!entity) {
          this.setCurrentEntity(entity);
        } else {
          this.message.warning(this.l('BasicArchives::UI:Message.CanNotFund', this.l('BasicArchives::ModelTitle:Joy.Erp.BasicArchives.ItemMasters.UnitGroup'), code));
        }
      });
    }
  }

  @debounce()
  uniqueCodeSetting() {
    var settingKey = 'UniqueCodeConfigration:Joy.Erp.BasicArchives.ItemMasters.UnitGroup';
    this.uniqueCodeSettingService.show(settingKey).afterClose.subscribe(result => {
      this.updateCodeValidators();
    });
  }

  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
    $event.stopPropagation();
    this.nzContextMenuService.create($event, menu);
  }

  closeMenu(): void {
    this.nzContextMenuService.close();
  }  

  getErrorMessage(fieldName: string): string {
    return this.getControlErrorMessage(this.validateForm, fieldName);
  }

  getControlErrorMessage(formGroup: any, fieldName: string): string {
    const control = formGroup.get(fieldName);
    if (control && control.invalid && (control.touched || control.dirty)) {
      if (control.hasError('required')) {
        return this.l('BasicArchives::UI:Validation:Required');
      }
      if (control.hasError('maxlength')) {
        return this.l('BasicArchives::UI:Validation:MaxLength', control.getError('maxlength').requiredLength);
      }
    }
    return '';
  }

  protected changeToEmpty() {
    this.validateForm.reset({...this.entityConfig.defaultValue, children: []}, { emitEvent: false });
    this.validateForm.setControl('children', this.fb.array([]));
    this.refreshFormValidationStatus();
    this.editState = EditState.Empty;
  }

  protected setCurrentEntity(entity: UnitGroupDto) {
    this.currentEntity = entity;
    var childrenFromGroups = entity.children.map(child => this.createChildFormGroup(child));
    this.validateForm.reset({
      ...this.currentEntity,
      children: []
    }, { emitEvent: false });

    this.validateForm.setControl('children', this.fb.array(childrenFromGroups));
    this.refreshFormValidationStatus();
    this.editState = EditState.View;
  }

  protected giveUpConfirm(): Promise<any> {
    return new Promise((resolve, reject) => {
      if (this.editState != EditState.Creating && this.editState != EditState.Editing)
        return reject();
      this.modal.confirm({
        nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
        nzContent: this.l('BasicArchives::UI:Confirm.Content.GiveUpConfirm'),
        nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
        nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
        nzOnOk: () => resolve(null),
      });
    });
  }

  protected checkDirty(): Promise<any> {
    return new Promise(resolve => {
      if (this.editState == EditState.Creating || this.editState == EditState.Editing) {
        this.modal.confirm({
          nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
          nzContent: this.l('BasicArchives::UI:Confirm.Content.ChangeStateConfirm'),
          nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
          nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
          nzOnOk: () => resolve(null),
        });
      } else {
        resolve(null);
      }
    });
  }
  
  protected refreshFormValidationStatus() {
    Object.keys(this.validateForm.controls).forEach(key => {
      this.validateForm.controls[key].markAsPristine();
      this.validateForm.controls[key].updateValueAndValidity();
    });
  }

  protected updateCodeValidators() {
    const codeControl = this.validateForm.get('code');
    const validators = [Validators.maxLength(200)];
    if (!this.codeInputDisabled) {
      validators.push(Validators.required);
    }
    codeControl.setValidators(validators);
    codeControl.updateValueAndValidity();
  }

  protected markFormGroupTouched(formGroup: FormGroup) {
    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.get(key);
      control.markAsTouched();
      control.updateValueAndValidity();
      
      if (control instanceof FormGroup) {
        this.markFormGroupTouched(control);
      } else if (control instanceof FormArray) {
        control.controls.forEach(arrayControl => {
          arrayControl.markAsTouched();
          arrayControl.updateValueAndValidity();
          if (arrayControl instanceof FormGroup) {
            this.markFormGroupTouched(arrayControl);
          }
        });
      }
    });
  }

  protected l(key: string, ...args: any[]): string {
    return this.localizationService.instant(key, ...args);
  }
}
